package com.mp.mqtt.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.ipm2020.common.util.CacheUtil;
import com.mp.ipm2020.common.util.RedisUtil;
import com.mp.ipm2020.mbg.util.ResolverDeviceDataUtil;
import com.mp.ipm2020.mbg.model.DeviceData;
import com.mp.ipm2020.mbg.model.DeviceInfo;
import com.mp.ipm2020.mbg.service.DeviceDataService;
import com.mp.ipm2020.mbg.service.DeviceInfoService;
import com.mp.mqtt.dto.DeviceSendData;
import com.mp.mqtt.service.DataToDbService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * @Auther adidasshe@mp.cn
 */
@Service
public class DataToDbServiceimpl implements DataToDbService {
    @Autowired
    private CacheUtil cacheUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private DeviceInfoService deviceInfoService;
    @Autowired
    DeviceDataService deviceDataService;

    @Autowired
    private ResolverDeviceDataUtil resolverDeviceDataUtil;
    @Value("${mqtt.topic}")
    private String topic;

    /**
     * 将设备上传的数据写入mysql数据表中
     *
     * @param id
     * @param obj
     */
    @Override
    public void addDeviceData(Long id, DeviceSendData obj) {
//        System.out.println("添加数据");
        DeviceData deviceData = new DeviceData();
        deviceData.setCreateTime(new Date());
        deviceData.setDeviceId(id);
        deviceData.setSwitch1(obj.s1);
        deviceData.setSwitch2(obj.s2);
        deviceData.setSwitch3(obj.s3);
        deviceData.setVoltage1(obj.v1 / 10d);
        deviceData.setVoltage2(obj.v2 / 10d);
        deviceData.setVoltage3(obj.v3 / 10d);
        deviceData.setCurrent1(obj.c1 / 10d);
        deviceData.setCurrent2(obj.c2 / 10d);
        deviceData.setCurrent3(obj.c3 / 10d);
        deviceData.setLeakageCurrent1(Math.round((Math.sqrt(obj.lc1 / 20.0) * 3.3 / 4096 * 2000) * 100) / 100d);
        deviceData.setLeakageCurrent2(Math.round((Math.sqrt(obj.lc2 / 20.0) * 3.3 / 4096 * 2000) * 100) / 100d);
        deviceData.setLeakageCurrent3(Math.round((Math.sqrt(obj.lc3 / 20.0) * 3.3 / 4096 * 2000) * 100) / 100d);
        deviceData.setUnbalancedState1(obj.us / 100d);
        deviceData.setCapacitanceSwitch1((obj.cs >> 1) & 1);
        deviceData.setCapacitanceSwitch2((obj.cs >> 2) & 1);
        deviceData.setCapacitanceSwitch3((obj.cs >> 3) & 1);
        deviceData.setCapacitanceSwitch4((obj.cs >> 4) & 1);
        deviceData.setCapacitanceSwitch5((obj.cs >> 5) & 1);
        deviceData.setCapacitanceSwitch6((obj.cs >> 6) & 1);
        deviceData.setCapacitanceSwitch7((obj.cs >> 7) & 1);
        deviceData.setCapacitanceSwitch8((obj.cs >> 8) & 1);
        deviceData.setCapacitanceSwitch9((obj.cs >> 9) & 1);
        deviceData.setCapacitanceSwitch10((obj.cs >> 10) & 1);
        deviceData.setCapacitanceSwitch11((obj.cs >> 11) & 1);
        deviceData.setCapacitanceSwitch12((obj.cs >> 12) & 1);
        deviceData.setCapacitanceSwitch13((obj.cs >> 13) & 1);
        deviceData.setCapacitanceSwitch14((obj.cs >> 14) & 1);
        deviceData.setCapacitanceSwitch15((obj.cs >> 15) & 1);
        deviceData.setCapacitanceSwitch16((obj.cs >> 16) & 1);
        deviceData.setCapacitanceSwitch17((obj.cs >> 17) & 1);
        deviceData.setCapacitanceSwitch18((obj.cs >> 18) & 1);
        deviceData.setPowerSwitch1((obj.ps >> 1) & 3);
        deviceData.setPowerSwitch2((obj.ps >> 2) & 3);
        deviceData.setPowerSwitch3((obj.ps >> 3) & 3);
        deviceData.setPowerSwitch4((obj.ps >> 4) & 3);
        deviceData.setPowerSwitch5((obj.ps >> 5) & 3);
        deviceData.setPowerSwitch6((obj.ps >> 6) & 3);
        deviceData.setPowerFactor1(obj.pf1 / 1000d);
        deviceDataService.save(deviceData);

    }

    /**
     * 查询缓存池及mysql设备表有无此设备数据，无则向数据库表中插入此设备
     *
     * @param deviceId
     */
    @Override
    public void addDeviceInfo(String deviceId, DeviceSendData obj) {
        DeviceInfo deviceInfo = new DeviceInfo();

        //如果缓存中没有该设备ID或者缓存池中没有数据
        if (redisUtil.sHasKey("deviceIds", deviceId) == false || redisUtil.sGetSetSize("deviceIds") == 0) {
            System.out.println(deviceId);
            //刷新缓存池
            getDeviceId();
        }
        //如果缓存池刷新后还没有该设备ID，则向数据库添加该设备
        if (redisUtil.sHasKey("deviceIds", deviceId) == false) {

            deviceInfo.setDeviceId(deviceId);
            deviceInfo.setSoftVersion(obj.sv);
            deviceInfoService.create(deviceInfo);
            System.out.println("写入数据库");
            getDeviceId();
        }

        int o = (int) redisUtil.get(deviceId);
        System.out.println(o);

        long id = Long.parseLong(o + "");
        //向数据表中添加设备数据
        addDeviceData(id, obj);


    }

    @PostConstruct //启动时执行该方法，但是会阻塞服务进程
    @Override
    public void init() {
//        System.out.println("开启数据写入mysql线程，将所有设备ID写入redis缓存池中");
        getDeviceId();
    }

    @Async
    @Override
    public void getData() {
        //消费者需要不断轮询队列，有消息便取出来
        while (true) {
            handlerData();
        }
    }

    /**
     * 开启事务处理缓存写入数据库
     */
//    @Transactional
    @Override
    public void handlerData() {
        //获取缓存队列数据
        if (redisUtil.lGetListSize(topic) != 0) {
            String data = cacheUtil.get(topic);
            System.out.println("处理数据：" + new Date() + data);
            HashMap<String, String> map = resolverDeviceDataUtil.resolver(data);
            System.out.println(map);
            //如果获取的数据不为空且格式正确
            if (map != null) {
                String deviceId = map.get("deviceId");
                String deviceData = map.get("data");
                //将字符串转化为java对象
                DeviceSendData deviceSendData = JSONObject.parseObject(deviceData, DeviceSendData.class);
                System.out.println(deviceId + " :" + deviceSendData);
                addDeviceInfo(deviceId, deviceSendData);
                //删除已经存储过的数据
                redisUtil.lpop(topic);
            }else {
                //删除不能解析的错误数据
                redisUtil.lpop(topic);
            }

        } else {
//                System.out.println("缓存队列为空");
        }

    }

    @Scheduled(cron = "0 */1 * * * ?")
    @Override
    public void getDataByScheduled() {
        getDeviceId();
    }


    @Override
    public void getDeviceId() {
        redisUtil.del("deviceIds");
        //获取所有的设备ID
        List<DeviceInfo> list = deviceInfoService.list();
        list.forEach(key -> {
//            System.out.println("key" + ":" + key.getDeviceId());
            //将所有设备id对应的外键ID缓存，避免每次插入设备数据先读取数据库
            redisUtil.set(key.getDeviceId(), key.getId());
            //添加所有设备ID进入缓存池set(value不可重复)
            redisUtil.sSet("deviceIds", key.getDeviceId());
        });
    }
}
